#include <Server.h>
#include <iostream>
#include <poll.h>
#include <map>
#include "threading.h"
#include <sys/epoll.h>
#include <sign_kernel.h>

Server::Server(/* args */)
    : mPort(8080), mIp("127.0.0.1"), mListenCounter(1)
{
    Socket::CreatSocket(AF_INET, SOCK_STREAM);
}

Server::Server(const int port, const char *ip, int listen)
    : mPort(port), mIp(ip), mListenCounter(listen)
{
    Socket::CreatSocket(AF_INET, SOCK_STREAM);
}

Server::~Server()
{
    Socket::CloseSocket();
}

void Server::setMaxListenCounter(int backlog)
{
    this->mListenCounter = backlog;
}

int Server::getMaxListenCounter(int backlog)
{
    return this->mListenCounter;
}

void Server::setListener(Server::ServerListener* serverListener)
{
    mServerListener = serverListener;
}

int Server::startListen(ServerEnum serverEnum)
{
    char buffer[1024] = { 0 };
    struct sockaddr_in address;
    bzero(&address, sizeof(address));
    address.sin_family = AF_INET;
    address.sin_port = htons(mPort);
    address.sin_addr.s_addr = inet_addr(mIp);
    Socket::Bind(&address, sizeof(address));

    Socket::Listen(mListenCounter);

    switch (serverEnum) {
    case ServerEnum::FORK : {
        struct sockaddr_in client_address;
        socklen_t client_address_len = sizeof(client_address);
        while (true) {
            int client_socket_fd = Socket::Accept(&client_address, &client_address_len);
            pid_t pid = fork();
            check("fork", pid);
            if (pid == 0) { /* 子进程 */
                CloseSocket();
                if (mServerListener != nullptr) {
                    Server::Client* client = new Server::Client();
                    client->fd = client_socket_fd;
                    client->addr = client_address;
                    client->addrlen = client_address_len;
                    mServerListener->callback(this, client);
                    close(client_socket_fd);
                    delete client;
                }
                exit(-1);
            } else {
                close(client_socket_fd);
            }
        }
    } break;
    case ServerEnum::THREAD : {
        struct sockaddr_in client_address;
        socklen_t client_address_len = sizeof(client_address);
        while (true) {
            int client_socket_fd = Socket::Accept(&client_address, &client_address_len);
            ServerThread *serverThread = new ServerThread();
            Server::Client* client = new Server::Client();
            client->fd = client_socket_fd;
            client->addr = client_address;
            client->addrlen = client_address_len;
            serverThread->init(this, client);
            serverThread->start();
        }
    } break;
    case ServerEnum::SELECT : {
        struct sockaddr_in client_address;
        socklen_t client_address_len = sizeof(client_address);
        fd_set rset, allset;
        std::vector<int> client;
        std::map<int, Server::Client> clientList;
        int maxfd = sockfd;
        int maxi = -1;

        FD_ZERO(&allset);
        FD_SET(sockfd, &allset);

        while (true) {
            rset = allset;
            int nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
            check("select", nready);
            if (FD_ISSET(sockfd, &rset)) {
                /* 有客户端请求连接 */
                int client_socket_fd = Socket::Accept(&client_address, &client_address_len);

                Server::Client serclist;
                serclist.fd = client_socket_fd;
                serclist.addr = client_address;
                serclist.addrlen = client_address_len;
                clientList[client_socket_fd] = serclist;

                bool link = mServerListener->connect(this, &serclist);
                if (link == false) { 
                    close(client_socket_fd);
                    clientList.erase(client_socket_fd);
                    continue;
                }

                if (client.size() >= FD_SETSIZE) {
                    printf("too many client");
                    exit(-1);
                }

                FD_SET(client_socket_fd, &allset);
                client.push_back(client_socket_fd);

                if (client_socket_fd > maxfd) {
                    maxfd = client_socket_fd;
                }
                if (nready == 1) continue;
            }
            /* 客户端发送数据 */
            for (auto it = client.begin(); it != client.end();) {
                int value = *it;
                if (FD_ISSET(value, &rset)) {
                    int len = Read(value, buffer, sizeof(buffer));
                    if (len == 0) { /* 断开连接 */
                        close(value);
                        FD_CLR(value, &allset);
                        it = client.erase(it);
                        clientList.erase(value);
                        continue;
                    } else {
                        bool link = mServerListener->recv(this, &clientList.at(value), buffer, len);
                        if (link == false) { /* 断开连接 */
                            close(value);
                            FD_CLR(value, &allset);
                            it = client.erase(it);
                            clientList.erase(value);
                            continue;
                        }
                    }
                }
                it++;
            }
        }
    } break;
    case ServerEnum::POLL : {
        struct sockaddr_in client_address;
        socklen_t client_len = sizeof(client_address);
        std::map<int, Server::Client> clientList;
        int client_socket_fd = 0;
        struct pollfd fds[1024];
        for (size_t i = 0; i < 1024; i++)
        {
            fds[i].fd = -1;
        }
        int fdslen = 0;
        
        fds[0].fd = sockfd;
        fds[0].events = POLLIN;

        while (true)
        {
            int nready = poll(fds, fdslen + 1, -1);
            check("poll", nready);

            if ((fds[0].revents & POLLIN) == POLLIN) {
                /* 有客户端请求连接 */
                client_socket_fd = Accept(&client_address, &client_len);

                Server::Client serclist;
                serclist.fd = client_socket_fd;
                serclist.addr = client_address;
                serclist.addrlen = client_len;
                clientList[client_socket_fd] = serclist;
                bool link = mServerListener->connect(this, &serclist);
                if (link == false) {
                    close(client_socket_fd);
                    clientList.erase(client_socket_fd);
                    continue;
                }
                int i = 0;
                for (;i < 1024; i++) {
                    if (fds[i].fd <= 0) {
                        fds[i].fd= client_socket_fd;
                        fds[i].events = POLLIN;
                        break;
                    }
                }
                if (fdslen < i) fdslen = i;

                if (fdslen == 1024) {
                    std::cerr << "too many client" << std::endl;
                    exit(-1);
                }
                if (--nready <= 0) continue;
            }
            for (int i = 1; i <= fdslen; i++) {
                if ((fds[i].revents & POLLIN) == POLLIN) {
                    int len = Read(fds[i].fd, buffer, sizeof(buffer));
                    if (len == 0) { /* 断开连接 */
                        close(fds[i].fd);
                        fds[i].fd = -1;
                        clientList.erase(fds[i].fd);
                        continue;
                    } else {
                        bool link = mServerListener->recv(this, &clientList.at(fds[i].fd), buffer, len);
                        if (link == false) { /* 断开连接 */
                            close(fds[i].fd);
                            fds[i].fd = -1;
                            clientList.erase(fds[i].fd);
                            continue;
                        }
                    }
                    if (--nready <= 0) break;
                }
            }
        }
    } break;
    case ServerEnum::EPOLL : {
        const int EPOLL_NUM = 5000;
        struct sockaddr_in client_address;
        socklen_t client_len = sizeof(client_address);
        int epollfd = epoll_create(EPOLL_NUM);
        check("epoll_create", epollfd);
        struct epoll_event envList[EPOLL_NUM];

        struct epoll_event env;
        env.events = EPOLLIN;
        env.data.fd = sockfd;
        int ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &env);
        check("epoll ctr", ret);

        while (true)
        {
            int nready = epoll_wait(epollfd, envList, EPOLL_NUM, -1);
            check("epoll wait", nready);
            for (size_t i = 0; i < nready; ++i)
            {
                if (!envList[i].events & EPOLLIN) {
                    continue;
                }
                if (envList[i].data.fd == sockfd) {
                    int client_socket_fd = Accept(&client_address, &client_len);

                    Server::Client *client = new Server::Client();
                    client->fd = client_socket_fd;
                    client->addr = client_address;
                    client->addrlen = client_len;

                    int link = mServerListener->connect(this, client);
                    if (link == false) { /* 断开连接 */
                        close(client->fd);
                        delete client;
                        continue;
                    }

                    env.events = EPOLLIN;
                    env.data.ptr = client;
                    ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, client_socket_fd, &env);
                    check("epoll ctl", ret);
                } else {
                    Server::Client *client = (Server::Client *)envList[i].data.ptr;
                    ret = Read(client->fd, buffer, sizeof(buffer));
                    if (ret == 0) { /* 断开连接 */
                        close(client->fd);
                        ret = epoll_ctl(epollfd, EPOLL_CTL_DEL, client->fd, NULL);
                        delete(client);
                    } else {
                        bool link = mServerListener->recv(this, client, buffer, ret);
                        if (link == false) { /* 断开连接 */
                            close(client->fd);
                            ret = epoll_ctl(epollfd, EPOLL_CTL_DEL, client->fd, NULL);
                            delete(client);
                        }
                    }
                }
            }
        }
        close(epollfd);
    } break;
    }
}
